'''
第十章
将 Datetime, Time 合并为一个时间列 Datetime ，同时把它作为索引后排序
'''
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 读取太阳辐射的数据集
df = pd.read_csv('data/solar.csv', usecols=['Data','Time',
                 'Radiation','Temperature'])
# 利用正则匹配时间格式字符串
solar_date = df.Data.str.extract('([/|\w]+\s).+')[0]
df['Data'] = pd.to_datetime(solar_date + df.Time)
df = df.drop(columns='Time').rename(columns={'Data':'Datetime'}
            ).set_index('Datetime').sort_index()
'''
每条记录时间的间隔显然并不一致，请解决如下问题
a.找出间隔时间的前三个最大值所对应的三组时间戳
'''
# 求间隔的差然后转成dt
s = df.index.to_series().reset_index(drop=True).diff().dt.total_seconds()
# 获取间隔最大的index
max_3 = s.nlargest(3).index
# 取对应的一组时间戳
df.index[max_3.union(max_3-1)]

'''
是否存在一个大致的范围，使得绝大多数的间隔时间都落在这个区间中？如果存在，请对此范围内的样本间隔秒数画出柱状图，设置 bins=50 
'''
res = s.mask((s>s.quantile(0.99))|(s<s.quantile(0.01)))
_ = plt.hist(res, bins=50)

'''
求如下指标对应的 Series ：
温度与辐射量的6小时滑动相关系数
'''
res = df.Radiation.rolling('6H').corr(df.Temperature)
res.tail(3)
'''
以三点、九点、十五点、二十一点为分割，该观测所在时间区间的温度均值序列
'''
# 抽样间隔6h 设置开头3h
res = df.Temperature.resample('6H', origin='03:00:00').mean()

'''
每个观测6小时前的辐射量（一般而言不会恰好取到，此时取最近时间戳对应的辐射量）
'''
my_dt = df.index.shift(freq='-6H')
int_loc = [df.index.get_indexer([i], method='nearest') for i in my_dt]
int_loc = np.array(int_loc).reshape(-1)
res = df.Radiation.iloc[int_loc]
res.index = df.index
res.tail(3)

target = pd.DataFrame(
    {
        "Time": df.index.shift(freq='-6H'),
        "Datetime": df.index,
    }
)
res = pd.merge_asof(
    target,
    df.reset_index().rename(columns={"Datetime": "Time"}),
    left_on="Time",
    right_on="Time",
    direction="nearest"
).set_index("Datetime").Radiation


'''
水果销量数据集
'''
df = pd.read_csv('data/fruit.csv')
df.head(3)
'''
每月上半月（15号及之前）与下半月葡萄销量的比值
'''
df.Date = pd.to_datetime(df.Date)
df_grape = df.query("Fruit == 'Grape'")
res = df_grape.groupby([np.where(df_grape.Date.dt.day<=15,
                        'First', 'Second'),df_grape.Date.dt.month]
                        )['Sale'].mean().to_frame().unstack(0
                        ).droplevel(0,axis=1)
res = (res.First/res.Second).rename_axis('Month')

'''
每月最后一天的生梨销量总和
'''
df[df.Date.dt.is_month_end].query("Fruit == 'Pear'"
                          ).groupby('Date').Sale.sum().head()

'''
每月最后一天工作日的生梨销量总和
'''
df[df.Date.isin(pd.date_range('20190101', '20191231',
                freq='BM'))].query("Fruit == 'Pear'"
                ).groupby('Date').Sale.sum().head()

'''
每月最后五天的苹果销量均值
'''
target_dt = df.drop_duplicates().groupby(df.Date.drop_duplicates(
            ).dt.month)['Date'].nlargest(5).reset_index(drop=True)


res = df.set_index('Date').loc[target_dt].reset_index(
            ).query("Fruit == 'Apple'")


res = res.groupby(res.Date.dt.month)['Sale'].mean(
            ).rename_axis('Month')

'''
按月计算周一至周日各品种水果的平均记录条数，行索引外层为水果名称，内层为月份，列索引为星期
'''
month_order = ['January','February','March','April',
                'May','June','July','August','September',
                'October','November','December']


week_order = ['Mon','Tue','Wed','Thu','Fri','Sat','Sum']

group1 = df.Date.dt.month_name().astype('category').cat.reorder_categories(
        month_order, ordered=True)


group2 = df.Fruit

group3 = df.Date.dt.dayofweek.replace(dict(zip(range(7),week_order))
         ).astype('category').cat.reorder_categories(
         week_order, ordered=True)


res = df.groupby([group1, group2,group3])['Sale'].count().to_frame(
         ).unstack(0).droplevel(0,axis=1)


res.head()

'''
按天计算向前10个工作日窗口的苹果销量均值序列，非工作日的值用上一个工作日的结果填充
'''
df_apple = df[(df.Fruit=='Apple')&(
              ~df.Date.dt.dayofweek.isin([5,6]))]


s = pd.Series(df_apple.Sale.values,
              index=df_apple.Date).groupby('Date').sum()


res = s.rolling('10D').mean().reindex(
              pd.date_range('20190101','20191231')).fillna(method='ffill')


res.head()